package com.didang;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import com.didang.exception.WheresVOIsNullException;
import com.didang.exception.WheresVOSqlIsNullException;

@Component
public class Query {

	private static final Logger logger = Logger.getLogger(Query.class);
	
	@Resource
	private JdbcTemplate jdbcTemplate;
	private SqlVO wheresVO;
	
	public Query(){
		
	}
	
	public Query(SqlVO __wheresVO){
		this.wheresVO = __wheresVO;
	}

	/**
	 * 查询单个Model
	 * @param <T>
	 * @param clazz
	 * @return
	 * @throws WheresVOIsNullException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws WheresVOSqlIsNullException 
	 * @throws NoSuchFieldException 
	 * @throws SecurityException 
	 */
	public <T> T selectOne(Class<T> clazz) throws WheresVOIsNullException, InstantiationException, IllegalAccessException, InvocationTargetException, WheresVOSqlIsNullException, SecurityException, NoSuchFieldException{
		String tableName = ModelHelper.getTableName(clazz);
		String selectSql = "select * from "+tableName+" where ";
		if(this.wheresVO == null) throw new WheresVOIsNullException();
		if(this.wheresVO.getSql() == null) throw new WheresVOSqlIsNullException();
		selectSql += this.wheresVO.getSql();
		logger.info(selectSql);
		List<Map<String, Object>> list = this.jdbcTemplate.queryForList(selectSql, this.wheresVO.getParams());
		if(list.size()<1) return null;
		Map<String, Object> map = list.get(0);
		T t = (T) clazz.newInstance();
		BeanUtils.populate(t, this.columnMapToFieldMap(map,clazz));
		return t;
	}
	
	/**
	 * 查询多个Model
	 * @param clazz
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws WheresVOIsNullException
	 * @throws InvocationTargetException
	 * @throws WheresVOSqlIsNullException 
	 * @throws NoSuchFieldException 
	 * @throws SecurityException 
	 */
	public <T> List<T> selectMany(Class<T> clazz) throws InstantiationException, IllegalAccessException, WheresVOIsNullException, InvocationTargetException, WheresVOSqlIsNullException, SecurityException, NoSuchFieldException{
		List<T> modelLists = new ArrayList<T>();
		String tableName = ModelHelper.getTableName(clazz);
		String selectSql = "select * from "+tableName+" where ";
		if(this.wheresVO == null) throw new WheresVOIsNullException();
		if(this.wheresVO.getSql() == null) throw new WheresVOSqlIsNullException();
		selectSql += this.wheresVO.getSql();
		logger.info(selectSql);
		List<Map<String, Object>> list = this.jdbcTemplate.queryForList(selectSql, this.wheresVO.getParams());
		T t = null;
		for(Map<String, Object> map : list){
			t = (T) clazz.newInstance();
			BeanUtils.populate(t, this.columnMapToFieldMap(map,clazz));
			modelLists.add(t);
		}
		return modelLists.size()>0?modelLists:null;
	}
	
	/**
	 * 把columnMap转成filedMap
	 * @param columnMap
	 * @param clazz
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 */
	private Map columnMapToFieldMap(Map columnMap,Class clazz) throws SecurityException, NoSuchFieldException{
		Map fieldMap = new HashMap();
		Map<String, String> colummFieldMap = ModelHelper.getColumnFiledMap(clazz);
		Set set = columnMap.keySet();
		Object value = null;
		String filedName = null;
		String columnName = null;
		for(Iterator it = set.iterator();it.hasNext();){
			columnName = (String) it.next();
			value = columnMap.get(columnName);
			filedName= colummFieldMap.get(columnName);
			fieldMap.put(filedName, value);
		}
		return fieldMap;
	}
	
	public SqlVO getWheresVO() {
		return wheresVO;
	}

	public void setWheresVO(SqlVO wheresVO) {
		this.wheresVO = wheresVO;
	}
}
